package com.kaisu.blog.application.user.service.impl;

import com.kaisu.blog.application.exception.TokenExpireException;
import com.kaisu.blog.application.properties.AuthProperties;
import com.kaisu.blog.application.user.service.JWTService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.util.Date;

/**
 * @author kaisu
 */
@Slf4j
@Service
public class JWTServiceImpl implements JWTService {
    private final AuthProperties properties;

    public JWTServiceImpl(@Qualifier("authProperties") AuthProperties properties) {
        this.properties = properties;
    }

    private Claims getAllClaims(String token) throws RuntimeException {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .verifyWith(getSignKey())
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
        } catch (Exception e) {
            log.error("token异常", e);
            throw new TokenExpireException();
        }
        return claims;
    }

    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + properties.getJwt().getClaims().getExpirationTimeMinutes() * 60 * 1000);
    }

    private String getAuthHeader(HttpServletRequest request) {
        return request.getHeader(properties.getJwt().getAuthHeader());
    }

    @Override
    public String generateToken(String account) {
        return Jwts.builder()
                .issuer(properties.getJwt().getClaims().getIssuer())
                .subject(account)
                .issuedAt(new Date(System.currentTimeMillis()))
                .expiration(generateExpirationDate())
                .signWith(getSignKey())
                .audience()
                .add(properties.getJwt().getClaims().getAudience())
                .and()
                .compact();
    }

    private SecretKey getSignKey() {
        byte[] keyBytes = Decoders.BASE64.decode(properties.getJwt().getSecret());
        return Keys.hmacShaKeyFor(keyBytes);
    }

    @Override
    public String validateToken(String token) {
        try {
            return getAllClaims(token).getSubject();
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    @Override
    public String getToken(HttpServletRequest request) {
        return getAuthHeader(request);
    }
}